using System;
using System.Collections;

namespace BilSimser.SharePoint.Common.Data
{
	/// <summary>
	/// Data structure representing a WSS List
	/// </summary>
	public class ListDescriptor
	{
		private string listName;
		private string listId;
		private ListItem[] listItems;

		/// <summary>
		/// WSS ID of list
		/// </summary>
		/// <remarks> equivalent to SPList.ID in the WSS OM</remarks> 
		public string ListId
		{
			get { return listId; }
			set { listId = value; }
		}

		/// <summary>
		/// Name of list
		/// </summary>
		/// <remarks> equivalent to SPList.Title in the WSS OM</remarks> 
		public string ListName
		{
			get { return listName; }
			set { listName = value; }
		}

		/// <summary>
		/// Array of list items. 
		/// </summary>
		/// <remarks>This may contain some or all of the items in the list, depending on the query used.</remarks>
		public ListItem[] ListItems
		{
			get { return listItems; }
			set { listItems = value; }
		}
	}

	/// <summary>
	/// Data structure representing an WSS List Item 
	/// </summary>
	public class ListItem
	{
		private int id;
		private Field[] fields = new Field[0];
		private Hashtable fieldIndexes;

		/// <summary>
		/// Gets or sets the id.
		/// </summary>
		/// <value>The id.</value>
		public int Id
		{
			get { return id; }
			set { id = value; }
		}

		/// <summary>
		/// Array of fields (columns) contained in the list item
		/// </summary>
		public Field[] Fields
		{
			get { return fields; }
			set { fields = value; }
		}

		/// <summary>
		/// Inits the field indexes.
		/// </summary>
		private void InitFieldIndexes()
		{
			fieldIndexes = new Hashtable();
			fieldIndexes.Clear();
			foreach (Field field in Fields)
			{
				if (!fieldIndexes.ContainsKey(field.Name))
					fieldIndexes.Add(field.Name, field);
			}
		}

		/// <summary>
		/// Default Constructor
		/// </summary>
		public ListItem()
		{
		}

		/// <summary>
		/// Constructor for creating a ListItem structure with data
		/// </summary>
		/// <param name="id">WSS ID of list item. (use 0 for new items)</param>
		/// <param name="values">Array of names and values used to populate the Fields array</param>
		/// <example> 
		/// ListItem newLI = new ListItem(0,"Title","This is a list item","Author","#1;Addys","Date",System.DateTime.Now.ToString());
		/// </example>
		public ListItem (int id, params string[] values)
		{
			int i = 0;
			this.id = id;
			while (i < values.Length)
			{
				Add(values[i], values[i + 1], false);
				i += 2;
			}
		}

		/// <summary>
		/// Adds a new field to the ListItem
		/// </summary>
		/// <param name="name">Field Name</param>
		/// <param name="fieldValue">Field Value</param>
		/// <param name="readOnly">Is this field Read Only?</param>
		public void Add (string name, string fieldValue, bool readOnly)
		{
			ArrayList fieldList = new ArrayList(Fields);
			fieldList.Add(new Field(name, fieldValue, readOnly));
			this.fields = new Field[fieldList.Count];
			fieldList.CopyTo(Fields);
		}

		/// <summary>
		/// Indexer for accessing fields by name. Returns null if specified field 
		/// name doesn't exist.
		/// </summary>
		public string this [string name]
		{
			get
			{
				if (fieldIndexes == null)
					InitFieldIndexes();

				if (fieldIndexes.ContainsKey(name))
					return ((Field) fieldIndexes[name]).Value;
				else
					return null;
			}
			set
			{
				if (fieldIndexes == null)
					InitFieldIndexes();

				if (fieldIndexes.ContainsKey(name))
					((Field) fieldIndexes[name]).Value = value;
				else
					throw new IndexOutOfRangeException();
			}
		}
	}

	/// <summary>
	/// Data structure representing a Field in a WSS List Item
	/// </summary>
	public class Field
	{
		private string name;
		private bool readOnly;
		private string fieldValue;

		/// <summary>
		/// Default Constructor
		/// </summary>
		public Field()
		{
		}

		/// <summary>
		/// Constructor for Field with values
		/// </summary>
		/// <param name="name">Field Name</param>
		/// <param name="val">Field Value</param>
		/// <param name="readOnly">Field isReadOnly</param>
		public Field (string name, string val, bool readOnly)
		{
			this.name = name;
			this.fieldValue = val;
			this.readOnly = readOnly;
		}

		/// <summary>
		/// Gets or sets the name.
		/// </summary>
		/// <value>The name.</value>
		public string Name
		{
			get { return name; }
			set { name = value; }
		}

		/// <summary>
		/// Gets or sets a value indicating whether [read only].
		/// </summary>
		/// <value><c>true</c> if [read only]; otherwise, <c>false</c>.</value>
		public bool ReadOnly
		{
			get { return readOnly; }
			set { readOnly = value; }
		}

		/// <summary>
		/// Gets or sets the value.
		/// </summary>
		/// <value>The value.</value>
		public string Value
		{
			get { return fieldValue; }
			set { fieldValue = value; }
		}
	}
}